#include "../include/DictProducer.h"
#include "../include/SplitTool.h"
#include "../include/Configuration.h"

#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using std::cout;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::ostringstream;

DictProducer::DictProducer(const string &dir)
: _splitTool(nullptr)
{
    pushFiles(dir);
}

DictProducer::DictProducer(const string &dir, SplitTool *splitTool) 
: _splitTool(splitTool)
{
    pushFiles(dir);
}

DictProducer::~DictProducer() {
    cout << "~DictProducer()" << endl;
}

void DictProducer::buildEnDict() {
    while (!_files.empty()) {
        string path = getFiles();
        ifstream ifs(path);
        if (!ifs.good()) {
            cout << "ifstream open error!" << endl;
            return;
        }

        string word;
        while (ifs >> word) {
            string ret;
            for (auto it = word.begin(); it != word.end(); ++it) {
                if (!ispunct(*it) && !isdigit(*it)) {
                    ret += tolower(*it);
                }
            }
            if (ret.size() == 0) {
                continue;
            }
            ++_dict[ret];
        }
        ifs.close();
    }
}

void DictProducer::buildCnDict(Configuration *pconf) {
    set<string> mySet = pconf->getStopWordList();
    while (!_files.empty()) {
        string path = getFiles();
        ifstream ifs(path);
        if (!ifs.good()) {
            cout << "ifstream open error!" << endl;
            return;
        }

        /* map<string, int> wordCount; */
        string lines;
        while (ifs >> lines) {
            vector<string> words = _splitTool->cut(lines);
            for (auto it = words.begin(); it != words.end(); ++it) {
                //cout << *it << " ";
                if (mySet.count(*it)) {
                    continue;
                }
                ++_dict[*it];
            }
        }
    }

}

void DictProducer::createIndex() {
        
    string path;
    if (_splitTool == nullptr) {
        path = "../data/engDict.dat";
    }
    else {
        path = "../data/cnDict.dat";
    }
    ifstream ifs(path);
    if (!ifs.good()) {
        cout << "ifstream open error!" << endl;
        return;
    }

    string line;
    int line_no = 1;
    while (getline(ifs, line)) {
        for (size_t idx = 0; idx != getLen(line); ++idx) {
            if (line[idx] == ' ') {
                break;
            }
            size_t nB = nBytesCode(line[idx]);
            string s = line.substr(idx, nB);
            idx += (nB - 1);
            /* ostringstream oss; */
            /* oss << line[idx]; */
            _index[s].insert(line_no);
        }
        line_no++;
    }
    ifs.close();

    int ret = chdir("../data");
    if (ret == -1) {
        perror("chdir");
        return;
    }

    ofstream ofs("dictIndex.dat", std::ios::out|std::ios::app);
    if (!ofs.good()) {
        cout <<"ofstrem open file error" << endl;
        return;
    }
    for (const auto &w: _index) {
        ostringstream oss;
        oss << w.first << " ";
        for (auto &no: w.second) {
            oss << no << " ";
        }
        oss << "\n";
        string s = oss.str();
        ofs << s;
    }
    ofs.close();
}

void DictProducer::storeDict(const char *filepath) {
    int ret = chdir("../data");
    if (ret == -1) {
        perror("chdir");
        return;
    }

    ofstream ofs(filepath, std::ios::out|std::ios::app);
    if (!ofs.good()) {
        cout <<"ofstrem open file error" << endl;
        return;
    }
    for (const auto &w: _dict) {
        ostringstream oss;
        oss << w.first << " " << w.second << "\n";
        string s = oss.str();
        ofs << s;
    }
    ofs.close();
}

void DictProducer::pushFiles(const string &dir) {
    DIR *dirp = opendir(dir.c_str());
    if (dirp == nullptr) {
        perror("opendir");
        exit(0);
    }
    struct dirent *pdirent;
    while ((pdirent = readdir(dirp)) != nullptr) {
        if (!strcmp(pdirent->d_name, ".") || !strcmp(pdirent->d_name, "..")) {
            continue;
        }
        string path = dir + "/" + pdirent->d_name;
        _files.push_back(path);
    }
}

string DictProducer::getFiles() {
    string tmp = _files.back();
    _files.pop_back();
    return tmp;
}

void DictProducer::pushDict(const string &word) {

}

/* void showFiles() const; */
void DictProducer::showDict() const {
    int count = 0;
    for (auto &elem: _dict) {
        cout << elem.first << ": " << elem.second << endl;
        count++;
        if (count >= 20) {
            break;
        }
    }
}
